﻿using Masuit.Tools.Logging;
using Opc.Ua.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LPLS.CollectionHardProtocol.OPCUAModules.OPCUABAseModule
{
    /// <summary>
    /// OPCUA的基础操作
    /// </summary>
    public abstract class LPLSOPCUABaseOP<T> where T : OPCUABaseDTO
    {

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="alllist"> </param>
        /// <param name="cycletime"> </param>
        public LPLSOPCUABaseOP(List<T> alllist,int cycletime) {


            AllOPCUAList=alllist; ;
            CycleTime=cycletime;
        }

        /// <summary>
        /// 循环时间周期
        /// </summary>
        public int CycleTime { get; set; }
        /// <summary>
        /// 所有的OPCUA连接 该组件下的
        /// </summary>
        public List<T> AllOPCUAList=  new List<T> ();

        /// <summary>
        /// 该组件下所有的失败的连接
        /// </summary>
        public List<T> FailList { get; set; }=new List<T> ();

        /// <summary>
        /// 该组件下的左右的成功的连接
        /// </summary>
        public List<T> SuccessList { get; set; } = new List<T>();
      
        /// <summary>
        /// 心跳检测  最少五秒  此函数需要放在 周期中
        /// </summary>
        /// <param name="pCUABaseDTOs"></param>
        /// <param name="cycleTime">周期</param>
        public virtual void JudgeConnection() 
        {
            //判断OPCUA 可以使用QZ
            Parallel.ForEach(AllOPCUAList, item =>
            {

                var clientStatus = item.OPCUAClient.ConnectStatus;
                ///如果断链 则需要重新启动
                if (!clientStatus)
                {
                    ///取消订阅
                    item.OPCUAClient.CancelAllNodeIdDatasSubscription();
                    ///关闭连接
                    item.OPCUAClient.CloseConnect();
                    ///加入失败组
                    FailList.Add(item);
                }
                else 
                {
                    SuccessList.Add(item);


                }

            });

        }

        /// <summary>
        /// 初始化函数  这里面涉及到了 订阅发布
        /// </summary>
        public virtual void Init() 
        { 
        
            Parallel.For (0,AllOPCUAList.Count, async i => 
            {
                ///打开OPCUA连接 默认匿名  之后可能需要更改
              await  AllOPCUAList[i].OPCUAClient.OpenConnectOfAnonymous();
                //判断是否连接成功
                if (AllOPCUAList[i].OPCUAClient.ConnectStatus)
                {
                    SuccessList.Add(AllOPCUAList[i]);
                    ///对数据进行订阅
                    var nodes = AllOPCUAList[i].Nodes;
                    if (nodes.Count > 0) { 
                    
                    var arry=nodes.ToArray();

                        var groupname = AllOPCUAList[i].GroupName;

                        AllOPCUAList[i].OPCUAClient.BatchNodeIdDatasSubscription(groupname,arry, AllOPCUAList[i].SubCallback);
                    }
                    else
                    {
                        LogManager.Info($"OpcUa 连接成功但是未找到相应的订阅node节点 连接url: {AllOPCUAList[i].OPCUAClient.URl}");
                    }
                }
                else 
                { 
                
                  FailList.Add (AllOPCUAList[i]);
                }
            } );      
        }

        /// <summary>
        /// 断线连接重连
        /// </summary>
        public virtual void FailOPCUAConnection() 
        {
            Parallel.For(0, FailList.Count, async i => 
            { 
            
            var d = FailList[i];
             await  d.OPCUAClient.OpenConnectOfAnonymous();


                if (d.OPCUAClient.ConnectStatus)
                {



                    SuccessList.Add (d);
                    FailList.Remove(d);
                }
            
            });
        }

        /// <summary>
        /// 批量读取更适合轮询每次都会打开新的连接 每次读取都会关闭
        /// </summary>
        public virtual void BatchRead()
        {

            if (AllOPCUAList.Count==0)
            {
                LogManager.Info("没有OPCUA连接，可能正在初始化 或者正在进行热重载 ！！！");

            }
            Parallel.For(0, AllOPCUAList.Count, async i =>
            {
                try
                {
                   await AllOPCUAList[i].OPCUAClient.OpenConnectOfAnonymous();
                    //判断是否连接成功
                    if (AllOPCUAList[i].OPCUAClient.ConnectStatus)
                    {
                      //  SuccessList.Add(AllOPCUAList[i]);
                        ///对数据进行订阅
                        var nodes = AllOPCUAList[i].Nodes;
                        if (nodes.Count > 0)
                        {

                            var arry = nodes.ToArray();

                            var groupname = AllOPCUAList[i].GroupName;

                            AllOPCUAList[i].BatchRead();
                        }
                        else
                        {
                            LogManager.Info($"OpcUa 连接成功但是未找到相应的node节点 连接url: {AllOPCUAList[i].OPCUAClient.URl}");
                        }
                    }
                    else
                    {

                        LogManager.Info($"OpcUa 连接失败 连接url: {AllOPCUAList[i].OPCUAClient.URl}");
                    }

                }
                catch (Exception ex)
                {

                    LogManager.Error(ex);
                }
                finally 
                {
                    AllOPCUAList[i].OPCUAClient.CloseConnect();
                }
              
               
            });
        }



        
    }
}
